package com.joker.demo.core.executor;


import com.alibaba.fastjson2.JSON;
import com.joker.demo.core.config.JobExecutorProperties;
import com.joker.demo.core.domain.bo.JobRegistryBO;
import com.joker.demo.core.domain.bo.JobRegistryDetailBO;
import com.joker.demo.core.domain.dto.JobExecutorResultDTO;
import com.joker.demo.core.domain.dto.MessageDTO;
import com.joker.demo.core.domain.dto.TaskExecuteRequestDTO;
import com.joker.demo.core.domain.dto.TaskExecuteResponseDTO;
import com.joker.demo.core.domain.dto.ThreadPoolMonitorDTO;
import com.joker.demo.core.domain.dto.EnvironmentMonitorDTO;
import com.joker.demo.core.domain.enums.JobRequestEnum;
import com.joker.demo.core.exception.BizException;
import com.joker.demo.core.executor.smart.TaskExecutionManager;
import com.joker.demo.core.executor.smart.ThreadPoolMonitor;
import com.joker.demo.core.executor.smart.EnvironmentMonitor;
import com.joker.demo.core.netty.client.NettyClient;
import com.joker.demo.core.netty.client.handler.NettyClientHandler;
import com.joker.demo.core.util.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.UUID;

/**
 * 任务执行器抽象基类
 * <p>
 * 这个类提供了任务执行器的核心功能，包括：
 * 1. 连接到调度中心
 * 2. 注册任务处理器
 * 3. 启动心跳机制
 * 4. 管理任务执行
 * 5. 提供任务提交、取消、状态查询等功能
 * <p>
 * 子类需要实现：
 * - getRegisterJobHandlers(): 返回要注册的任务处理器列表
 * - executeTask(): 执行具体的任务逻辑
 *
 * @author : feixiang.li
 * @since : 2025-07-24 15:19
 */
public abstract class JobExecutor {

    /**
     * 日志记录器
     */
    private static final Logger log = LoggerFactory.getLogger(JobExecutor.class);

    /**
     * 任务执行器配置信息
     */
    private final JobExecutorProperties properties;

    /**
     * Netty客户端，用于与调度中心通信
     */
    private NettyClient nettyClient;

    /**
     * 任务执行管理器，负责管理任务的执行状态和线程池
     */
    private TaskExecutionManager taskExecutionManager;

    /**
     * 环境监控定时器，用于定期发送环境监控数据
     */
    private java.util.Timer environmentMonitorTimer;

    /**
     * 构造函数
     *
     * @param properties 任务执行器配置
     */
    protected JobExecutor(JobExecutorProperties properties) {
        this.properties = properties;
    }

    /**
     * 普通Java项目初始化方法
     * 执行以下步骤：
     * 1. 连接到调度中心
     * 2. 注册任务处理器
     * 3. 启动心跳检测
     * 4. 初始化任务执行管理器
     */
    public void start() {
        try {
            log.info("开始初始化普通Java项目任务执行器");
            log.info("配置信息: {}", properties);

            // 第一步：连接到调度中心
            log.info("正在连接调度中心...");
            connectToScheduler(properties);

            // 第二步：注册任务处理器到调度中心
            log.info("正在注册任务处理器...");
            registerJobHandlers(getRegisterJobHandlers());

            // 第三步：启动心跳机制，保持与调度中心的连接
            log.info("正在启动心跳机制...");
            startHeartbeat();

            // 第四步：初始化任务执行管理器
            log.info("正在初始化任务执行管理器...");
            taskExecutionManager = new TaskExecutionManager(this);

            log.info("普通Java项目任务执行器初始化完成");

        } catch (Exception e) {
            log.error("初始化普通Java项目任务执行器失败", e);
            throw new BizException("初始化任务执行器失败", e);
        }
    }

    /**
     * Spring Boot项目初始化方法
     * 与普通Java项目初始化类似，但专门为Spring Boot环境设计
     */
    public void startSpringBoot() {
        try {
            log.info("开始初始化Spring Boot项目任务执行器");
            log.info("配置信息: {}", properties);

            // 连接到调度中心
            log.info("正在连接调度中心...");
            connectToScheduler(properties);

            // 注册任务处理器
            log.info("正在注册任务处理器...");
            registerJobHandlers(getRegisterJobHandlers());

            // 启动心跳机制
            log.info("正在启动心跳机制...");
            startHeartbeat();

            // 初始化任务执行管理器
            log.info("正在初始化任务执行管理器...");
            taskExecutionManager = new TaskExecutionManager(this);
            
            // 如果启用了线程池监控，则设置监控器
            if (properties.getThreadPoolMonitor().isEnabled()) {
                ThreadPoolMonitor threadPoolMonitor = new ThreadPoolMonitor(properties, taskExecutionManager);
                taskExecutionManager.setThreadPoolMonitor(threadPoolMonitor);
                
                // 启动监控数据发送
                String registerKey = IpUtil.getIpWithExternalPriority() + ":" + properties.getPort();
                taskExecutionManager.startMonitorDataSender(
                    registerKey, 
                    properties.getGroupName(), 
                    properties.getThreadPoolMonitor().getIntervalSeconds()
                );
                
                log.info("线程池监控器初始化成功，监控间隔：{}秒", properties.getThreadPoolMonitor().getIntervalSeconds());
            }

            // 启动环境监控数据发送
            startEnvironmentMonitor();

            log.info("Spring Boot项目任务执行器初始化完成");

        } catch (Exception e) {
            log.error("初始化Spring Boot项目任务执行器失败", e);
            throw new BizException("初始化任务执行器失败", e);
        }
    }

    /**
     * 注册任务处理器到调度中心
     *
     * @param jobRegistryList 要注册的任务处理器列表
     */
    private void registerJobHandlers(List<JobRegistryDetailBO> jobRegistryList) {
        // 检查是否有任务处理器需要注册
        if (jobRegistryList == null || jobRegistryList.isEmpty()) {
            log.warn("没有任务处理器需要注册");
            return;
        }

        // 构建注册信息
        JobRegistryBO jobRegistryBO = new JobRegistryBO();
        // 设置执行器组名
        jobRegistryBO.setGroupName(properties.getGroupName());
        // 设置任务处理器列表
        jobRegistryBO.setJobRegistryList(jobRegistryList);
        // 生成注册标识：IP:端口
        String registerKey = IpUtil.getIp() + ":" + properties.getPort();
        jobRegistryBO.setRegisterKey(registerKey);

        log.info("准备注册任务处理器: {}", JSON.toJSONString(jobRegistryBO));

        try {
            // 通过Netty客户端发送注册请求
            nettyClient.registerJobHandlers(jobRegistryBO);
            log.info("任务处理器注册成功");
        } catch (Exception e) {
            log.error("注册任务处理器失败", e);
            throw new BizException("注册任务处理器失败", e);
        }
    }

    /**
     * 连接到调度中心
     *
     * @param config 执行器配置信息
     */
    private void connectToScheduler(JobExecutorProperties config) {
        log.info("正在连接到调度中心: {}", config.getServerUrl());

        try {
            // 创建Netty客户端处理器
            NettyClientHandler clientHandler = new NettyClientHandler(this);
            // 创建Netty客户端
            nettyClient = new NettyClient(config, clientHandler, this);
            // 建立连接
            nettyClient.connect();
            log.info("成功连接到调度中心");
        } catch (Exception e) {
            log.error("连接调度中心失败", e);
            throw new BizException("连接调度中心失败", e);
        }
    }

    /**
     * 启动心跳机制
     * 心跳机制用于：
     * 1. 保持与调度中心的连接
     * 2. 定期向调度中心报告执行器状态
     * 3. 检测连接是否断开
     */
    private void startHeartbeat() {
        log.info("正在启动心跳机制...");

        try {
            nettyClient.startHeartbeat();
            log.info("心跳机制启动成功");
        } catch (Exception e) {
            log.error("启动心跳机制失败", e);
            throw new BizException("启动心跳机制失败", e);
        }
    }

    /**
     * 停止任务执行器
     * <p>
     * 执行以下清理工作：
     * 1. 关闭任务执行管理器
     * 2. 断开与调度中心的连接
     * 3. 停止环境监控定时器
     */
    public void stop() {
        log.info("正在停止任务执行器...");
        try {
            // 关闭任务执行管理器
            if (taskExecutionManager != null) {
                taskExecutionManager.shutdown();
                log.info("任务执行管理器已关闭");
            }

            // 停止环境监控定时器
            if (environmentMonitorTimer != null) {
                environmentMonitorTimer.cancel();
                environmentMonitorTimer = null;
                log.info("环境监控定时器已停止");
            }

            // 断开Netty客户端连接
            if (nettyClient != null) {
                nettyClient.disconnect();
                log.info("Netty客户端已断开连接");
            }

            log.info("任务执行器已停止");
        } catch (Exception e) {
            log.error("停止任务执行器时发生异常", e);
        }
    }

    /**
     * 提交任务到执行队列
     *
     * @param params 任务参数
     * @return 任务ID
     */
    public Long submitTask(TaskExecuteRequestDTO params) {
        if (taskExecutionManager == null) {
            throw new BizException("任务执行管理器未初始化");
        }
        return taskExecutionManager.submitTask(params);
    }


    public void sendTaskResult(TaskExecuteResponseDTO taskExecuteResultDTO) {
        if (nettyClient == null) {
            throw new BizException("Netty客户端未初始化");
        }

        MessageDTO messageDTO = new MessageDTO(JobRequestEnum.TASK_RESULT.getCode(), UUID.randomUUID().toString(), JSON.toJSONString(taskExecuteResultDTO));
        nettyClient.sendMessage(messageDTO);
    }

    /**
     * 发送线程池监控数据
     *
     * @param monitorData 监控数据
     */
    public void sendMonitorData(ThreadPoolMonitorDTO monitorData) {
        if (nettyClient == null) {
            throw new BizException("Netty客户端未初始化");
        }

        MessageDTO messageDTO = new MessageDTO(JobRequestEnum.THREAD_POOL_MONITOR.getCode(), UUID.randomUUID().toString(), JSON.toJSONString(monitorData));
        nettyClient.sendMessage(messageDTO);
    }

    /**
     * 发送环境监控数据
     *
     * @param monitorData 环境监控数据
     */
    public void sendEnvironmentMonitorData(EnvironmentMonitorDTO monitorData) {
        if (nettyClient == null) {
            throw new BizException("Netty客户端未初始化");
        }

        MessageDTO messageDTO = new MessageDTO(JobRequestEnum.ENVIRONMENT_MONITOR.getCode(), UUID.randomUUID().toString(), JSON.toJSONString(monitorData));
        nettyClient.sendMessage(messageDTO);
    }

    /**
     * 启动环境监控数据发送
     * 每隔10秒钟收集并发送环境监控数据到调度器
     */
    private void startEnvironmentMonitor() {
        log.info("正在启动环境监控数据发送，间隔：10秒");
        
        try {
            // 创建定时器
            environmentMonitorTimer = new java.util.Timer("EnvironmentMonitorTimer", true);
            
            // 生成注册键
            String registerKey = IpUtil.getIp() + ":" + properties.getPort();
            
            // 创建定时任务
            java.util.TimerTask environmentMonitorTask = new java.util.TimerTask() {
                @Override
                public void run() {
                    try {
                        // 收集环境监控数据
                        EnvironmentMonitorDTO monitorData = EnvironmentMonitor.collectEnvironmentData(
                            registerKey, 
                            properties.getGroupName()
                        );
                        
                        // 发送环境监控数据
                        sendEnvironmentMonitorData(monitorData);
                        
                        log.debug("环境监控数据发送成功，执行器：{}", registerKey);
                        
                    } catch (Exception e) {
                        log.error("发送环境监控数据失败，执行器：{}，错误：{}", registerKey, e.getMessage(), e);
                    }
                }
            };
            
            // 启动定时任务，延迟0秒，间隔10秒
            environmentMonitorTimer.schedule(environmentMonitorTask, 0, 10000);
            
            log.info("环境监控数据发送启动成功");
            
        } catch (Exception e) {
            log.error("启动环境监控数据发送失败", e);
            throw new BizException("启动环境监控数据发送失败", e);
        }
    }


    /**
     * 取消正在执行的任务
     *
     * @param taskId 任务ID
     * @return true表示取消成功，false表示取消失败
     */
    public boolean cancelTask(Long taskId) {
        if (taskExecutionManager == null) {
            throw new BizException("任务执行管理器未初始化");
        }
        return taskExecutionManager.cancelTask(taskId);
    }

    /**
     * 获取所有任务注册的执行器信息
     * 子类必须实现此方法，返回要注册到调度中心的任务处理器列表
     *
     * @return 任务注册信息列表
     */
    public abstract List<JobRegistryDetailBO> getRegisterJobHandlers();

    /**
     * 执行具体的任务
     * 当调度中心发送任务过来时，会调用此方法执行具体的任务逻辑
     * 子类必须实现此方法，提供具体的任务执行逻辑
     *
     * @param taskExecuteRequestDTO 执行参数，包含上游任务结果、任务分片或任务参数
     * @return 执行结果
     */
    public abstract JobExecutorResultDTO executeTask(TaskExecuteRequestDTO taskExecuteRequestDTO);
}
